package utils

import (
	"database/sql"
	"errors"
	"strconv"
	"time"
	"tizhi_front/model"
	"tizhi_front/response"
)

func GradeAtoi(gradeS string) (grade int, err error) {
	if len(gradeS) != 2 {
		err = errors.New("unknown current grade " + gradeS)
	} else {
		grade, err = strconv.Atoi(gradeS[1:])
	}
	return
}

func SexBtos(sex byte) (gender string, err error) {
	if sex == 1 {
		gender = "男"
	} else if sex == 2 {
		gender = "女"
	} else {
		err = errors.New("unknown sex" + strconv.Itoa(int(sex)))
	}
	return
}

func SexStob(gender string) (sex byte, err error) {
	if gender == "男" {
		sex = 1
	} else if gender == "女" {
		sex = 2
	} else {
		err = errors.New("unknown gender" + gender)
	}
	return
}

func BirthdayTtos(birthday time.Time) (birthdayS string) {
	if !birthday.IsZero() {
		birthdayS = birthday.Format("2006-01-02")
	}
	return
}

func ClassAtoi(classS string) (class int, err error) {
	if len(classS) != 7 {
		err = errors.New("unknown current class " + classS)
	} else {
		class, err = strconv.Atoi(classS[5:])
	}
	return
}

func NullFloat64ToFloat32(nullFloat64 sql.NullFloat64, nullValue float32) (float float32) {
	if nullFloat64.Valid {
		float = float32(nullFloat64.Float64)
	} else {
		float = nullValue
	}
	return
}

func GetUserScoreInfo(uid int64) (userScoreInfo response.UserScoreInfo, err error) {
	student := model.Student4{}
	school := model.School0{}
	err = student.SelectById(uid)
	if err != nil {
		return
	}
	err = school.SelectById(student.SchoolId)
	if err != nil {
		return
	}
	err = getUserInfo(&student, &school, &userScoreInfo.UserInfo)
	if err != nil {
		return
	}
	err = getScoreInfo(uid, school.SchoolType, &student, &userScoreInfo)
	return
}

func getUserInfo(student *model.Student4, school *model.School0, userInfo *response.UserInfo) (err error) {
	userInfo.Name = student.Name
	userInfo.PicUrl = student.PicUrl
	userInfo.NickName = student.NickName
	userInfo.Phone = student.Phone
	userInfo.StudentId = student.SchoolRollId
	userInfo.SchoolName = school.Name
	userInfo.Gender, err = SexBtos(student.Sex)
	userInfo.Height = float32(student.Height)
	userInfo.Weight = float32(student.Weight)
	if err != nil {
		return
	}
	userInfo.Grade, err = GradeAtoi(student.CurrentGrade)
	if err != nil {
		return
	}
	userInfo.Class, err = ClassAtoi(student.CurrentClass)
	if err != nil {
		return
	}
	userInfo.Birth = BirthdayTtos(student.Birthday)
	return
}

func getScoreInfo(uid int64, schoolType byte, student *model.Student4, userScoreInfo *response.UserScoreInfo) (err error) {
	switch schoolType {
	case 1:
		if userScoreInfo.UserInfo.Grade == 1 || userScoreInfo.UserInfo.Grade == 2 {
			err = getScoreInfoPrimary12(uid, userScoreInfo)
			if err != nil {
				return
			}
		} else if userScoreInfo.UserInfo.Grade == 3 || userScoreInfo.UserInfo.Grade == 4 {
			err = getScoreInfoPrimary34(uid, userScoreInfo)
			if err != nil {
				return
			}
		} else if userScoreInfo.UserInfo.Grade == 5 || userScoreInfo.UserInfo.Grade == 6 {
			err = getScoreInfoPrimary56(uid, userScoreInfo)
			if err != nil {
				return
			}
		} else {
			err = errors.New("unknown grade " + strconv.Itoa(userScoreInfo.UserInfo.Grade))
			return
		}
		break
	case 4:
		if userScoreInfo.UserInfo.Grade != 1 && userScoreInfo.UserInfo.Grade != 2 && userScoreInfo.UserInfo.Grade != 3 {
			err = errors.New("unknown grade " + strconv.Itoa(userScoreInfo.UserInfo.Grade))
			return
		}
		if student.Sex == 1 {
			err = getScoreInfoHighMale(uid, userScoreInfo)
			if err != nil {
				return
			}
		} else if student.Sex == 2 {
			err = getScoreInfoHighFemale(uid, userScoreInfo)
			if err != nil {
				return
			}
		} else {
			err = errors.New("unknown sex " + strconv.Itoa(int(student.Sex)))
			return
		}
		break
	case 6:
		if userScoreInfo.UserInfo.Grade != 1 && userScoreInfo.UserInfo.Grade != 2 && userScoreInfo.UserInfo.Grade != 3 {
			err = errors.New("unknown grade " + strconv.Itoa(userScoreInfo.UserInfo.Grade))
			return
		}
		if student.Sex == 1 {
			err = getScoreInfoHighMale(uid, userScoreInfo)
			if err != nil {
				return
			}
		} else if student.Sex == 2 {
			err = getScoreInfoHighFemale(uid, userScoreInfo)
			if err != nil {
				return
			}
		} else {
			err = errors.New("unknown sex " + strconv.Itoa(int(student.Sex)))
			return
		}
		break
	default:
		err = errors.New("unknown school type " + strconv.Itoa(int(schoolType)))
		return
	}
	err = getScoreInfoClass(student.SchoolId, student.CurrentClass, &userScoreInfo.ScoreInfo)
	if err != nil {
		return
	}
	err = getScoreInfoBlock(student.ExperimentAreaId, &userScoreInfo.ScoreInfo)
	if err != nil {
		return
	}
	err = getScoreInfoCity(student.CityId, &userScoreInfo.ScoreInfo)
	return
}

func getScoreInfoPrimary12(uid int64, userScoreInfo *response.UserScoreInfo) (err error) {
	score := model.Score0{}
	err = score.SelectByStudentIdOrderByMeasurementDateDesc(uid)
	if err != nil {
		return
	}
	userScoreInfo.ScoreInfo.TotalScore = float32(score.PhysicalTotalScore)
	err = getEachItemScores(5,
		[]string{"体重指数", "肺活量", "50米跑", "坐位体前屈", "一分钟跳绳"},
		[]float32{float32(score.BodyMassIndexBasicScore), float32(score.VitalCapacityBasicScore), float32(score.FiftyMetersBasicScore), float32(score.SitAndReachBasicScore), float32(score.OneMinuteRopeSkippingBasicScore)},
		[]string{score.BodyMassIndexLevel, score.VitalCapacityLevel, score.FiftyMetersLevel, score.SitAndReachLevel, score.OneMinuteRopeSkippingLevel},
		&userScoreInfo.ScoreInfo.EachItemScores)
	if err != nil {
		return
	}
	err = getExpandItemScores(4,
		[]string{"体脂百分比", "握力", "反应能力", "平衡能力"},
		[]string{score.BodyFatLevel, score.GripStrengthLevel, score.ResponseCapabilityLevel, score.BalanceAbilityLevel},
		&userScoreInfo.ScoreInfo.ExpandItemScores)
	if err != nil {
		return
	}
	userScoreInfo.ScoreInfo.PhysicalFunctionItem = 1
	userScoreInfo.ScoreInfo.PhysicalQualityItem = []int{2, 3, 4}
	err = getScoreInfoBmi(uid, score.BodyMassIndexLevel, &userScoreInfo.ScoreInfo)
	return
}

func getScoreInfoPrimary34(uid int64, userScoreInfo *response.UserScoreInfo) (err error) {
	score := model.Score3{}
	err = score.SelectByStudentIdOrderByMeasurementDateDesc(uid)
	if err != nil {
		return
	}
	userScoreInfo.ScoreInfo.TotalScore = float32(score.PhysicalTotalScore)
	err = getEachItemScores(6,
		[]string{"体重指数", "肺活量", "50米跑", "坐位体前屈", "一分钟跳绳", "一分钟仰卧起坐"},
		[]float32{float32(score.BodyMassIndexBasicScore), float32(score.VitalCapacityBasicScore), float32(score.FiftyMetersBasicScore), float32(score.SitAndReachBasicScore), float32(score.OneMinuteRopeSkippingBasicScore), float32(score.OneMinuteSitUpBasicScore)},
		[]string{score.BodyMassIndexLevel, score.VitalCapacityLevel, score.FiftyMetersLevel, score.SitAndReachLevel, score.OneMinuteRopeSkippingLevel, score.OneMinuteSitUpLevel},
		&userScoreInfo.ScoreInfo.EachItemScores)
	if err != nil {
		return
	}
	err = getExpandItemScores(5,
		[]string{"体脂百分比", "握力", "反应能力", "平衡能力", "纵跳"},
		[]string{score.BodyFatLevel, score.GripStrengthLevel, score.ResponseCapabilityLevel, score.BalanceAbilityLevel, score.VerticalJumpLevel},
		&userScoreInfo.ScoreInfo.ExpandItemScores)
	if err != nil {
		return
	}
	userScoreInfo.ScoreInfo.PhysicalFunctionItem = 1
	userScoreInfo.ScoreInfo.PhysicalQualityItem = []int{2, 3, 4, 5}
	err = getScoreInfoBmi(uid, score.BodyMassIndexLevel, &userScoreInfo.ScoreInfo)
	return
}

func getScoreInfoPrimary56(uid int64, userScoreInfo *response.UserScoreInfo) (err error) {
	score := model.Score4{}
	err = score.SelectByStudentIdOrderByMeasurementDateDesc(uid)
	if err != nil {
		return
	}
	userScoreInfo.ScoreInfo.TotalScore = float32(score.PhysicalTotalScore)
	err = getEachItemScores(7,
		[]string{"体重指数", "肺活量", "50米跑", "坐位体前屈", "一分钟跳绳", "一分钟仰卧起坐", "50米x8往返跑"},
		[]float32{float32(score.BodyMassIndexBasicScore), float32(score.VitalCapacityBasicScore), float32(score.FiftyMetersBasicScore), float32(score.SitAndReachBasicScore), float32(score.OneMinuteRopeSkippingBasicScore), float32(score.OneMinuteSitUpBasicScore), float32(score.ShuttleRunBasicScore)},
		[]string{score.BodyMassIndexLevel, score.VitalCapacityLevel, score.FiftyMetersLevel, score.SitAndReachLevel, score.OneMinuteRopeSkippingLevel, score.OneMinuteSitUpLevel, score.ShuttleRunLevel},
		&userScoreInfo.ScoreInfo.EachItemScores)
	if err != nil {
		return
	}
	err = getExpandItemScores(5,
		[]string{"体脂百分比", "握力", "反应能力", "平衡能力", "纵跳"},
		[]string{score.BodyFatLevel, score.GripStrengthLevel, score.ResponseCapabilityLevel, score.BalanceAbilityLevel, score.VerticalJumpLevel},
		&userScoreInfo.ScoreInfo.ExpandItemScores)
	if err != nil {
		return
	}
	userScoreInfo.ScoreInfo.PhysicalFunctionItem = 1
	userScoreInfo.ScoreInfo.PhysicalQualityItem = []int{2, 3, 4, 5, 6}
	err = getScoreInfoBmi(uid, score.BodyMassIndexLevel, &userScoreInfo.ScoreInfo)
	return
}

func getScoreInfoHighMale(uid int64, userScoreInfo *response.UserScoreInfo) (err error) {
	score := model.Score5{}
	err = score.SelectByStudentIdOrderByMeasurementDateDesc(uid)
	if err != nil {
		return
	}
	userScoreInfo.ScoreInfo.TotalScore = float32(score.PhysicalTotalScore)
	err = getEachItemScores(7,
		[]string{"体重指数", "肺活量", "50米跑", "坐位体前屈", "立定跳远", "引体向上", "1000米跑"},
		[]float32{float32(score.BodyMassIndexBasicScore), float32(score.VitalCapacityBasicScore), float32(score.FiftyMetersBasicScore), float32(score.SitAndReachBasicScore), float32(score.StandingLongJumpBasicScore), float32(score.ChinningBasicScore), float32(score.OneThousandMetersBasicScore)},
		[]string{score.BodyMassIndexLevel, score.VitalCapacityLevel, score.FiftyMetersLevel, score.SitAndReachLevel, score.StandingLongJumpLevel, score.ChinningLevel, score.OneThousandMetersLevel},
		&userScoreInfo.ScoreInfo.EachItemScores)
	if err != nil {
		return
	}
	err = getExpandItemScores(5,
		[]string{"体脂百分比", "握力", "反应能力", "平衡能力", "纵跳"},
		[]string{score.BodyFatLevel, score.GripStrengthLevel, score.ResponseCapabilityLevel, score.BalanceAbilityLevel, score.VerticalJumpLevel},
		&userScoreInfo.ScoreInfo.ExpandItemScores)
	if err != nil {
		return
	}
	userScoreInfo.ScoreInfo.PhysicalFunctionItem = 1
	userScoreInfo.ScoreInfo.PhysicalQualityItem = []int{2, 3, 4, 5, 6}
	err = getScoreInfoBmi(uid, score.BodyMassIndexLevel, &userScoreInfo.ScoreInfo)
	return
}

func getScoreInfoHighFemale(uid int64, userScoreInfo *response.UserScoreInfo) (err error) {
	score := model.Score6{}
	err = score.SelectByStudentIdOrderByMeasurementDateDesc(uid)
	if err != nil {
		return
	}
	userScoreInfo.ScoreInfo.TotalScore = float32(score.PhysicalTotalScore)
	err = getEachItemScores(7,
		[]string{"体重指数", "肺活量", "50米跑", "坐位体前屈", "立定跳远", "一分钟仰卧起坐", "800米跑"},
		[]float32{float32(score.BodyMassIndexBasicScore), float32(score.VitalCapacityBasicScore), float32(score.FiftyMetersBasicScore), float32(score.SitAndReachBasicScore), float32(score.StandingLongJumpBasicScore), float32(score.OneMinuteSitUpBasicScore), float32(score.EightHundredMetersBasicScore)},
		[]string{score.BodyMassIndexLevel, score.VitalCapacityLevel, score.FiftyMetersLevel, score.SitAndReachLevel, score.StandingLongJumpLevel, score.OneMinuteSitUpLevel, score.EightHundredMetersLevel},
		&userScoreInfo.ScoreInfo.EachItemScores)
	if err != nil {
		return
	}
	err = getExpandItemScores(5,
		[]string{"体脂百分比", "握力", "反应能力", "平衡能力", "纵跳"},
		[]string{score.BodyFatLevel, score.GripStrengthLevel, score.ResponseCapabilityLevel, score.BalanceAbilityLevel, score.VerticalJumpLevel},
		&userScoreInfo.ScoreInfo.ExpandItemScores)
	if err != nil {
		return
	}
	userScoreInfo.ScoreInfo.PhysicalFunctionItem = 1
	userScoreInfo.ScoreInfo.PhysicalQualityItem = []int{2, 3, 4, 5, 6}
	err = getScoreInfoBmi(uid, score.BodyMassIndexLevel, &userScoreInfo.ScoreInfo)
	return
}

func getEachItemScores(num int, subject []string, scores []float32, levels []string, itemUserInfo *[]response.ItemScoreInfo) (err error) {
	physicalFitness := model.PhysicalFitness0{}
	*itemUserInfo = make([]response.ItemScoreInfo, num)
	for i := 0; i < num; i++ {
		err = physicalFitness.SelectBySubject(subject[i])
		if err != nil {
			return
		}
		(*itemUserInfo)[i].ItemName = physicalFitness.Name
		(*itemUserInfo)[i].ItemLabel = physicalFitness.Label
		if levels[i] == "缺测" {
			(*itemUserInfo)[i].ItemScore = -1
		} else {
			(*itemUserInfo)[i].ItemScore = scores[i]
		}
		(*itemUserInfo)[i].UpgradeInfo = physicalFitness.Comment
		(*itemUserInfo)[i].SchemeLabelId = int(physicalFitness.LabelId)
	}
	return
}

func getExpandItemScores(num int, subject []string, levels []string, itemUserInfo *[]response.ItemScoreInfo) (err error) {
	physicalFitness := model.PhysicalFitness0{}
	*itemUserInfo = make([]response.ItemScoreInfo, num)
	for i := 0; i < 4; i++ {
		if levels[i] == "缺测" {
			err = physicalFitness.SelectBySubject(subject[i])
			if err != nil {
				return
			}
			(*itemUserInfo)[i].ItemName = physicalFitness.Name
			(*itemUserInfo)[i].ItemLabel = levels[i]
			(*itemUserInfo)[i].ItemScore = -1
		} else {
			err = physicalFitness.SelectBySubjectLevel(subject[i], levels[i])
			if err != nil {
				return
			}
			(*itemUserInfo)[i].ItemName = physicalFitness.Name
			(*itemUserInfo)[i].ItemLabel = levels[i]
			(*itemUserInfo)[i].ItemScore = 0
			(*itemUserInfo)[i].UpgradeInfo = physicalFitness.Comment
		}
	}
	return
}

func getScoreInfoClass(schoolId int64, class string, allScoreInfo *response.AllScoreInfo) (err error) {
	student := model.StudentE{}
	classRank, err := student.SelectCountBySchoolIdCurrentClassScoreGreaterEqual(schoolId, class, float64(allScoreInfo.TotalScore))
	if err != nil {
		return
	}
	allScoreInfo.ClassRank = int(classRank)
	classStudentNum, err := student.SelectCountBySchoolIdCurrentClass(schoolId, class)
	allScoreInfo.ClassStudentNum = int(classStudentNum)
	return
}

func getScoreInfoBlock(experimentAreaId int64, allScoreInfo *response.AllScoreInfo) (err error) {
	student := model.StudentE{}
	blockRank, err := student.SelectCountByExperimentAreaIdScoreGreaterEqual(experimentAreaId, float64(allScoreInfo.TotalScore))
	if err != nil {
		return
	}
	allScoreInfo.BlockRank = int(blockRank)
	blockStudentNum, err := student.SelectCountByExperimentAreaId(experimentAreaId)
	allScoreInfo.BlockStudentNum = int(blockStudentNum)
	return
}

func getScoreInfoCity(cityId int64, allScoreInfo *response.AllScoreInfo) (err error) {
	student := model.StudentE{}
	cityRank, err := student.SelectCountByCityIdScoreGreaterEqual(cityId, float64(allScoreInfo.TotalScore))
	if err != nil {
		return
	}
	allScoreInfo.CityRank = int(cityRank)
	cityStudentNum, err := student.SelectCountByCityId(cityId)
	allScoreInfo.CityStudentNum = int(cityStudentNum)
	return
}

func getScoreInfoBmi(uid int64, bodyMassIndexLevel string, allScoreInfo *response.AllScoreInfo) (err error) {
	switch bodyMassIndexLevel {
	case "肥胖":
		allScoreInfo.BmiLevel = 3
		break
	case "超重":
		allScoreInfo.BmiLevel = 2
		break
	case "正常":
		allScoreInfo.BmiLevel = 1
		break
	case "低体重":
		allScoreInfo.BmiLevel = 0
		break
	case "缺测":
		allScoreInfo.BmiLevel = -1
		break
	default:
		err = errors.New("unknown body mass index level" + bodyMassIndexLevel)
		return
	}
	bodyShape := model.BodyShape1{}
	bodyShapes, err := bodyShape.SelectAll()
	if err != nil {
		return
	}
	allScoreInfo.BmiComment = make([]string, len(bodyShapes))
	allScoreInfo.BmiAnalyze = make([]string, len(bodyShapes))
	for i := 0; i < len(bodyShapes); i++ {
		allScoreInfo.BmiComment[i] = bodyShapes[i].Comment
		allScoreInfo.BmiAnalyze[i] = bodyShapes[i].Analysis
	}
	score2 := model.Score2{}
	scores, err := score2.SelectAllByStudentIdOrderByMeasurementDateAsc(uid)
	if err != nil {
		return
	}
	allScoreInfo.BmiScoreChange = make([]response.YearScore, len(scores))
	for i := 0; i < len(scores); i++ {
		allScoreInfo.BmiScoreChange[i].Score = float32(scores[i].BodyMassIndexBasicScore)
		allScoreInfo.BmiScoreChange[i].TestTime = scores[i].MeasurementDate.Format("2006-01-02")
	}
	return
}
